package com.yt.fras.config;


import com.yt.fras.config.impl.CustomizeAuthenticationEntryPoint;
import com.yt.fras.config.impl.CustomizeSessionInformationExpiredStrategy;
import com.yt.fras.filter.JwtAuthTokenFilter;
import com.yt.fras.handler.*;
import com.yt.fras.pojo.entity.Permission;
import com.yt.fras.service.PermissionService;
import com.yt.fras.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;

import java.util.List;

/**
 * ClassName:SecurityConfig
 * Package:com.yt.fras.config
 * Description:
 * 安全管理配置
 *
 * @date:2021/8/15 14:11
 * @author:yt
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 密码加密策略
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 登录成功处理逻辑
     */
    @Autowired
    CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;

    /**
     * 登录失败处理逻辑
     */
    @Autowired
    CustomizeAuthenticationFailureHandler authenticationFailureHandler;

    /**
     * 注销成功处理逻辑
     */
    @Autowired
    CustomizeLogoutSuccessHandler logoutSuccessHandler;

    /**
     * 权限拒绝处理逻辑
     */
    @Autowired
    CustomizeAccessDeniedHandler accessDeniedHandler;

    /**
     * 匿名用户访问无权限资源时的异常
     */
    @Autowired
    CustomizeAuthenticationEntryPoint authenticationEntryPoint;

    /**
     * 会话失效(账号被挤下线)处理逻辑
     */
    @Autowired
    CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    @Autowired
    private JwtAuthTokenFilter jwtAuthTokenFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
        //记住我功能
        //http.rememberMe()
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();
        List<Permission> allPermission = permissionService.getAllPermission();
        allPermission.forEach((p -> {
            // 将该规则添加
            authorizeRequests.antMatchers(p.getUrl()).hasAnyAuthority(p.getPermissionCode());
        }));
        authorizeRequests.antMatchers("/fras/test/**", "/fras/test1/**", "/fras/test2/**", "/fras/test3/**", "/fras/test4/**", "/fras/test5/**",  "/fras/register/**", "/fras/getIpLocation/**", "/fras/resetPassword/**", "/fras/captcha/**", "/swagger-ui/**", "/druid/**", "/fras/session/invalid", "/v3/**").permitAll()
                .anyRequest().authenticated()
                //登入
                .and().formLogin().loginProcessingUrl("/fras/login")
                //允许所有用户
                .permitAll()
                //登录成功处理逻辑
                .successHandler(authenticationSuccessHandler)
                //登录失败处理逻辑
                .failureHandler(authenticationFailureHandler)
                //注销
                .and().logout().logoutUrl("/fras/logout")
                .addLogoutHandler(new SecurityContextLogoutHandler())
                .deleteCookies("SESSION")
                //注销成功处理逻辑
                .logoutSuccessHandler(logoutSuccessHandler)
                //异常处理(权限拒绝、登录失效等)
                .and().exceptionHandling()
                //权限拒绝处理逻辑
                .accessDeniedHandler(accessDeniedHandler)
                //匿名用户访问无权限资源时的异常处理;
                .authenticationEntryPoint(authenticationEntryPoint)
                //会话管理
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .maximumSessions(1)
                .expiredSessionStrategy(sessionInformationExpiredStrategy);

        http.addFilterBefore(jwtAuthTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //所需要用到的静态资源，允许访问
        web.ignoring().antMatchers("/swagger-ui.html",
                "/swagger-ui/**",
                "/swagger-resources/**",
                "/v2/api-docs",
                "/v3/api-docs",
                "/webjars/**");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置认证方式
        auth.userDetailsService(userDetailsService);
    }


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}